Skip to content

perf(adapters): metadata-only availability probe — stop importing all 9 adapters on tools/list - #409

Merged
debugmcpdev merged 1 commit into
mainfrom
perf/401-metadata-only-adapter-probe
Aug 22, 2026
Merged

perf(adapters): metadata-only availability probe — stop importing all 9 adapters on tools/list#409
debugmcpdev merged 1 commit into
mainfrom
perf/401-metadata-only-adapter-probe

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Fixes #401

On the dist/source distribution, adapters load lazily per session — but the availability probe defeated that: isAdapterAvailable was literally try { await loadAdapter() }, so the first tools/list (and create_debug_session / list_supported_languages via the same getSupportedLanguagesAsync() path) imported and instantiated all nine @debugmcp/adapter-* packages, permanently, into the heap of a server that may only ever debug Python.

Change

  • New injectable PackageResolver seam on AdapterLoader (third constructor arg, mirroring the existing ModuleLoader seam). createDefaultPackageResolver():
    1. createRequire(import.meta.url).resolve(packageName) — presence via Node resolution, no module execution. ERR_PACKAGE_PATH_NOT_EXPORTED counts as installed (package present, ESM-only exports map).
    2. Fallback: fs.access over the loader's two existing monorepo fallback paths.
  • isAdapterAvailable: cache-hit short-circuit (a genuinely-loaded factory) → resolver probe. No import, no factory instantiation.
  • loadAdapter is untouched — full import + instantiation happen at the first real use of a language (AdapterRegistry.create()).
  • listAvailableAdapters metadata comes from its static known-adapter table as before; the live-factory attach refinement still applies when a factory was actually loaded.

Scope decisions (as discussed in the issue)

  • list_supported_languages' per-language getFactory() for modes + toolchain validate is deliberately unchanged: it's an explicit informational call with a 30s validation cache, and skipping the factory would silently turn launch.available from a real toolchain probe into assumed-true. The issue's stated goal — bounding "the server that answered initialize and one tools/list" — is met by fixing the probe.
  • Trade-off: a present-but-broken package (missing factory export, corrupt build) now reports installed: true and surfaces its error at first load, with the existing install-hint message.
  • Container mode unaffected (adapters pre-registered into the registry); npx bundle unaffected (batteries-included imports all 9 eagerly by design).

Measured (mem-bench, this machine, Windows)

node scripts/mem-bench.mjs --target dist --scenario idle,tools, median RSS over 5 trials. The metric for this issue is the tools/list step cost (after-tools-list − after-initialize):

after-initialize after-tools-list tools/list step
before 109.2 MB 114.1 MB +4.9 MB
after 98.1 MB 98.8 MB +0.7 MB

(The absolute after-initialize difference is #400's lazy transports, which this branch is rebased on; the before-baseline predates it.)

Tests

  • New metadata-only availability probe describe: probe returns availability without any moduleLoader.load call; cache short-circuit skips re-probing; listAvailableAdapters covers all 9 with zero imports.
  • New createDefaultPackageResolver describe: resolve-success, exports-map-rejection-as-installed, fs fallback (platform-safe file URLs), nothing-resolves.
  • The old load-based availability tests were superseded and removed — two of them had also silently become dependent on the local packages/*/dist being built (real fs hits).
  • Full npm test green, npm run lint clean.

🤖 Generated with Claude Code

… 9 adapters on tools/list

isAdapterAvailable no longer imports and instantiates the adapter package;
it asks an injectable PackageResolver whether the package (or a monorepo
fallback build) is present on disk. Full import + factory instantiation
stays where it belongs: the first real loadAdapter for a language. The
first tools/list / create_debug_session / list_supported_languages call
no longer drags every installed @debugmcp/adapter-* package into the heap
(issue #401).

Trade-off (as scoped in the issue): a present-but-broken package reports
installed:true and surfaces its error at first load with the existing
install-hint message. list_supported_languages' per-language getFactory
for modes/validate is deliberately unchanged — an explicit informational
call with a 30s validation cache.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@debugmcpdev
debugmcpdev merged commit 375ec58 into main Aug 22, 2026
10 checks passed
@debugmcpdev
debugmcpdev deleted the perf/401-metadata-only-adapter-probe branch August 22, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(adapters): first tools/list imports and instantiates all 9 adapter packages permanently

2 participants